import 'package:dio/dio.dart';
import 'package:retrofit/retrofit.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../types/app_types.dart';

part 'api_service.g.dart';

/**
 * API 响应基础类
 */
@JsonSerializable(genericArgumentFactories: true)
class ApiResponse<T> {
  final bool success;
  final String? message;
  final T? data;
  final String? error;

  const ApiResponse({
    required this.success,
    this.message,
    this.data,
    this.error,
  });

  factory ApiResponse.fromJson(
    Map<String, dynamic> json,
    T Function(Object? json) fromJsonT,
  ) =>
      _$ApiResponseFromJson(json, fromJsonT);

  Map<String, dynamic> toJson(Object Function(T value) toJsonT) =>
      _$ApiResponseToJson(this, toJsonT);
}

/**
 * 用户信息
 */
@JsonSerializable()
class User {
  final int id;
  final String username;
  final String email;
  final String? firstName;
  final String? lastName;
  final DateTime createdAt;
  final DateTime updatedAt;

  const User({
    required this.id,
    required this.username,
    required this.email,
    this.firstName,
    this.lastName,
    required this.createdAt,
    required this.updatedAt,
  });

  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
  Map<String, dynamic> toJson() => _$UserToJson(this);
}

/**
 * 登录响应
 */
@JsonSerializable()
class LoginResponse {
  final String accessToken;
  final String refreshToken;
  final User user;

  const LoginResponse({
    required this.accessToken,
    required this.refreshToken,
    required this.user,
  });

  factory LoginResponse.fromJson(Map<String, dynamic> json) =>
      _$LoginResponseFromJson(json);
  Map<String, dynamic> toJson() => _$LoginResponseToJson(this);
}

/**
 * 登录请求
 */
@JsonSerializable()
class LoginRequest {
  final String username;
  final String password;

  const LoginRequest({
    required this.username,
    required this.password,
  });

  factory LoginRequest.fromJson(Map<String, dynamic> json) =>
      _$LoginRequestFromJson(json);
  Map<String, dynamic> toJson() => _$LoginRequestToJson(this);
}

/**
 * 注册请求
 */
@JsonSerializable()
class RegisterRequest {
  final String username;
  final String email;
  final String password;
  final String? firstName;
  final String? lastName;

  const RegisterRequest({
    required this.username,
    required this.email,
    required this.password,
    this.firstName,
    this.lastName,
  });

  factory RegisterRequest.fromJson(Map<String, dynamic> json) =>
      _$RegisterRequestFromJson(json);
  Map<String, dynamic> toJson() => _$RegisterRequestToJson(this);
}

/**
 * 同步请求
 */
@JsonSerializable()
class SyncRequest {
  final List<Folder> folders;
  final List<Note> notes;
  final DateTime lastSyncTime;

  const SyncRequest({
    required this.folders,
    required this.notes,
    required this.lastSyncTime,
  });

  factory SyncRequest.fromJson(Map<String, dynamic> json) =>
      _$SyncRequestFromJson(json);
  Map<String, dynamic> toJson() => _$SyncRequestToJson(this);
}

/**
 * 同步响应
 */
@JsonSerializable()
class SyncResponse {
  final List<Folder> folders;
  final List<Note> notes;
  final DateTime serverTime;
  final bool hasMore;

  const SyncResponse({
    required this.folders,
    required this.notes,
    required this.serverTime,
    required this.hasMore,
  });

  factory SyncResponse.fromJson(Map<String, dynamic> json) =>
      _$SyncResponseFromJson(json);
  Map<String, dynamic> toJson() => _$SyncResponseToJson(this);
}

/**
 * API 服务接口定义
 */
@RestApi()
abstract class ApiService {
  factory ApiService(Dio dio, {String baseUrl}) = _ApiService;

  // ========== 认证相关 ==========

  /**
   * 用户登录
   */
  @POST('/auth/login/')
  Future<ApiResponse<LoginResponse>> login(@Body() LoginRequest request);

  /**
   * 用户注册
   */
  @POST('/auth/register/')
  Future<ApiResponse<User>> register(@Body() RegisterRequest request);

  /**
   * 刷新令牌
   */
  @POST('/auth/refresh/')
  Future<ApiResponse<LoginResponse>> refreshToken(@Body() Map<String, String> request);

  /**
   * 用户登出
   */
  @POST('/auth/logout/')
  Future<ApiResponse<String>> logout();

  // ========== 用户相关 ==========

  /**
   * 获取当前用户信息
   */
  @GET('/users/me/')
  Future<ApiResponse<User>> getCurrentUser();

  // ========== 笔记相关 ==========

  /**
   * 获取笔记列表
   */
  @GET('/notes/')
  Future<ApiResponse<List<Note>>> getNotes();

  /**
   * 创建笔记
   */
  @POST('/notes/')
  Future<ApiResponse<Note>> createNote(@Body() Note note);

  /**
   * 更新笔记
   */
  @PUT('/notes/{id}/')
  Future<ApiResponse<Note>> updateNote(@Path('id') int id, @Body() Note note);

  /**
   * 删除笔记
   */
  @DELETE('/notes/{id}/')
  Future<ApiResponse<String>> deleteNote(@Path('id') int id);

  // ========== 文件夹相关 ==========

  /**
   * 获取文件夹列表
   */
  @GET('/folders/')
  Future<ApiResponse<List<Folder>>> getFolders();

  /**
   * 创建文件夹
   */
  @POST('/folders/')
  Future<ApiResponse<Folder>> createFolder(@Body() Folder folder);

  // ========== 同步相关 ==========

  /**
   * 同步数据
   */
  @POST('/sync/')
  Future<ApiResponse<SyncResponse>> syncData(@Body() SyncRequest request);
}

/**
 * API 客户端实现
 */
class ApiClient {
  late final Dio _dio;
  late final ApiService _apiService;
  String? _accessToken;
  String? _refreshToken;
  
  ApiClient({String? baseUrl}) {
    _dio = Dio();
    _setupInterceptors();
    _apiService = _ApiService(_dio, baseUrl: baseUrl ?? 'http://localhost:8000/api/v1');
  }

  ApiService get service => _apiService;

  /**
   * 设置拦截器
   */
  void _setupInterceptors() {
    // 请求拦截器 - 添加认证头
    _dio.interceptors.add(InterceptorsWrapper(
      onRequest: (options, handler) async {
        if (_accessToken != null) {
          options.headers['Authorization'] = 'Bearer $_accessToken';
        }
        handler.next(options);
      },
      onError: (error, handler) async {
        // 处理 401 错误，尝试刷新令牌
        if (error.response?.statusCode == 401 && _refreshToken != null) {
          try {
            await _refreshAccessToken();
            // 重试原请求
            final options = error.requestOptions;
            options.headers['Authorization'] = 'Bearer $_accessToken';
            final response = await _dio.fetch(options);
            handler.resolve(response);
            return;
          } catch (e) {
            // 刷新失败，清除认证信息
            await clearAuth();
          }
        }
        handler.next(error);
      },
    ));

    // 日志拦截器
    _dio.interceptors.add(LogInterceptor(
      requestBody: true,
      responseBody: true,
      logPrint: (obj) => print('[API] $obj'),
    ));
  }

  /**
   * 刷新访问令牌
   */
  Future<void> _refreshAccessToken() async {
    if (_refreshToken == null) throw Exception('No refresh token available');

    final response = await _apiService.refreshToken({
      'refresh': _refreshToken!,
    });

    if (response.success && response.data != null) {
      _accessToken = response.data!.accessToken;
      _refreshToken = response.data!.refreshToken;
      await _saveTokens();
    } else {
      throw Exception('Failed to refresh token');
    }
  }

  /**
   * 设置认证信息
   */
  Future<void> setAuth(String accessToken, String refreshToken) async {
    _accessToken = accessToken;
    _refreshToken = refreshToken;
    await _saveTokens();
  }

  /**
   * 保存令牌到本地存储
   */
  Future<void> _saveTokens() async {
    final prefs = await SharedPreferences.getInstance();
    if (_accessToken != null) {
      await prefs.setString('access_token', _accessToken!);
    }
    if (_refreshToken != null) {
      await prefs.setString('refresh_token', _refreshToken!);
    }
  }

  /**
   * 从本地存储加载令牌
   */
  Future<void> loadTokens() async {
    final prefs = await SharedPreferences.getInstance();
    _accessToken = prefs.getString('access_token');
    _refreshToken = prefs.getString('refresh_token');
  }

  /**
   * 清除认证信息
   */
  Future<void> clearAuth() async {
    _accessToken = null;
    _refreshToken = null;
    final prefs = await SharedPreferences.getInstance();
    await prefs.remove('access_token');
    await prefs.remove('refresh_token');
  }

  /**
   * 检查是否已认证
   */
  bool get isAuthenticated => _accessToken != null;

  /**
   * 检查网络连接
   */
  Future<bool> checkConnection() async {
    try {
      final response = await _dio.get('/health/');
      return response.statusCode == 200;
    } catch (e) {
      return false;
    }
  }
}